package com.ipan.kits.concurrent;

import java.util.concurrent.TimeUnit;

/**
 * 线程相关工具类.
 * 
 * 1. 处理了InterruptedException的sleep
 * 
 * 2. 正确的InterruptedException处理方法
 */
public class ThreadUtil {

	/**
	 * 纯粹为了提醒下处理InterruptedException的正确方式，除非你是在写不可中断的任务.
	 */
	public static void handleInterruptedException() {
		Thread.currentThread().interrupt(); // 重置中断状态，保证后续处理程序能够正确识别当前线程是否被中断；
	}

	/**
	 * 结束线程，调用此方法后，线程将抛出 {@link InterruptedException}异常
	 *
	 * @param thread
	 *            线程
	 * @param isJoin
	 *            是否等待结束
	 */
	public static void interrupt(Thread thread, boolean isJoin) {
		if (null != thread && false == thread.isInterrupted()) {
			thread.interrupt();
			if (isJoin) {
				waitForDie(thread);
			}
		}
	}

	/**
	 * 等待当前线程结束. 调用 {@link Thread#join()} 并忽略 {@link InterruptedException}
	 */
	public static void waitForDie() {
		waitForDie(Thread.currentThread());
	}

	/**
	 * 等待线程结束. 调用 {@link Thread#join()} 并忽略 {@link InterruptedException}
	 *
	 * @param thread
	 *            线程
	 */
	public static void waitForDie(Thread thread) {
		if (null == thread) {
			return;
		}

		boolean dead = false;
		do {
			try {
				thread.join();
				dead = true;
			} catch (InterruptedException e) {
				// ignore
			}
		} while (false == dead);
	}

	/**
	 * 创建新线程，非守护线程，正常优先级，线程组与当前线程的线程组一致
	 *
	 * @param runnable
	 *            {@link Runnable}
	 * @param name
	 *            线程名
	 * @return {@link Thread}
	 * @since 3.1.2
	 */
	public static Thread newThread(Runnable runnable, String name) {
		final Thread t = newThread(runnable, name, false);
		if (t.getPriority() != Thread.NORM_PRIORITY) {
			t.setPriority(Thread.NORM_PRIORITY);
		}
		return t;
	}

	/**
	 * 创建新线程
	 *
	 * @param runnable
	 *            {@link Runnable}
	 * @param name
	 *            线程名
	 * @param isDaemon
	 *            是否守护线程
	 * @return {@link Thread}
	 * @since 4.1.2
	 */
	public static Thread newThread(Runnable runnable, String name, boolean isDaemon) {
		final Thread t = new Thread(null, runnable, name);
		t.setDaemon(isDaemon);
		return t;
	}

	/**
	 * 挂起当前线程
	 *
	 * @param timeout
	 *            挂起的时长
	 * @param timeUnit
	 *            时长单位
	 * @return 被中断返回false，否则true
	 */
	public static boolean sleep(Number timeout, TimeUnit timeUnit) {
		try {
			timeUnit.sleep(timeout.longValue());
		} catch (InterruptedException e) {
			return false;
		}
		return true;
	}

	/**
	 * 挂起当前线程
	 *
	 * @param millis
	 *            挂起的毫秒数
	 * @return 被中断返回false，否则true
	 */
	public static boolean sleep(Number millis) {
		if (millis == null) {
			return true;
		}
		return sleep(millis.longValue());
	}

	/**
	 * 挂起当前线程
	 *
	 * @param millis
	 *            挂起的毫秒数
	 * @return 被中断返回false，否则true
	 * @since 5.3.2
	 */
	public static boolean sleep(long millis) {
		if (millis > 0) {
			try {
				Thread.sleep(millis);
			} catch (InterruptedException e) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 考虑{@link Thread#sleep(long)}方法有可能时间不足给定毫秒数，此方法保证sleep时间不小于给定的毫秒数
	 *
	 * @param millis
	 *            给定的sleep时间
	 * @return 被中断返回false，否则true
	 * @see ThreadUtil#sleep(Number)
	 */
	public static boolean safeSleep(Number millis) {
		if (millis == null) {
			return true;
		}

		return safeSleep(millis.longValue());
	}

	/**
	 * 考虑{@link Thread#sleep(long)}方法有可能时间不足给定毫秒数，此方法保证sleep时间不小于给定的毫秒数
	 *
	 * @param millis
	 *            给定的sleep时间
	 * @return 被中断返回false，否则true
	 * @see ThreadUtil#sleep(Number)
	 * @since 5.3.2
	 */
	public static boolean safeSleep(long millis) {
		long done = 0;
		long before;
		long spendTime;
		while (done >= 0 && done < millis) {
			before = System.currentTimeMillis();
			if (false == sleep(millis - done)) {
				return false;
			}
			spendTime = System.currentTimeMillis() - before;
			if (spendTime <= 0) {
				// Sleep花费时间为0或者负数，说明系统时间被拨动
				break;
			}
			done += spendTime;
		}
		return true;
	}

	/**
	 * 停止线程池 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. 
	 * 如果超时, 则调用shutdownNow,
	 * 取消在workQueue中Pending的任务,并中断所有阻塞函数. 如果仍超時，則強制退出.
	 * 另对在shutdown时线程本身被调用中断做了处理.
	 * @deprecated 请使用ThreadPoolUtil.gracefulShutdown
	 * @see com.ipan.kits.concurrent.threadpool.ThreadPoolUtil
	 */
//	public static void shutdownAndAwaitTermination(ExecutorService pool) {
//		if (pool != null && !pool.isShutdown()) {
//			pool.shutdown();
//			try {
//				if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
//					pool.shutdownNow();
//					if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
//						ExceptionUtil.wrapRuntime("Pool did not terminate");
//					}
//				}
//			} catch (InterruptedException ie) {
//				pool.shutdownNow();
//				Thread.currentThread().interrupt();
//			}
//		}
//	}

}
